package org.xqp.hrm.service.impl;

import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.xqp.hrm.config.HighlightResultMapper;
import org.xqp.hrm.doc.CourseDoc;
import org.xqp.hrm.dto.CourseSearchDto;
import org.xqp.hrm.repository.CourseElasticsearchRepository;
import org.xqp.hrm.service.ICourseESService;
import org.xqp.hrm.util.PageList;
import org.xqp.hrm.vo.AggPageList;
import org.xqp.hrm.vo.TermsAggBucket;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class CourseESServiceImpl implements ICourseESService {

    @Autowired
    private CourseElasticsearchRepository repository;

    @Autowired
    private ElasticsearchTemplate template;

    @Autowired
    private HighlightResultMapper resultMapper;


    // 添加课程
    @Override
    public void save(CourseDoc doc) {
        repository.save(doc);
    }

    /**
     * 根据条件搜索课程
     */
    @Override
    public PageList<CourseDoc> search(CourseSearchDto dto) {

        // 创建查询条件构建器
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

        // 排序
        if (StringUtils.isNotEmpty(dto.getSortField())){// 判断前端传过来的分页条件
            String sortField = "onlineTime"; // 默认使用时间作为排序字段
            switch (dto.getSortField()){ // 判断以什么字段作为排序方式
                case "jg": sortField = "price";break;
                case "xl": sortField = "saleCount";break;
                case "pl": sortField = "commentCount";break;
                case "rq": sortField = "viewCount";break;
                case "xp": sortField = "onlineTime";break;
            }
            SortOrder sortOrder = SortOrder.DESC; // 默认排序是倒叙
            // 判断前端传过来的排序方式不为空且为升序，将排序方式改为升序
            if(dto.getSortType() != null && dto.getSortType().equalsIgnoreCase("asc")){
                sortOrder = SortOrder.ASC;
            }
            searchQueryBuilder.withSort(SortBuilders.fieldSort(sortField).order(sortOrder));
        }

        // 分页
        searchQueryBuilder.withPageable(PageRequest.of(dto.getPage() - 1, dto.getRows()));

        // 条件
        //组合查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 添加must   这里面放的是关键字查询 keyword
        if(StringUtils.isNotEmpty(dto.getKeyword())){ // 判断前端有没有关键字查询
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", dto.getKeyword()));
        }

        // 添加filter  其余的筛选条件加入这里
        //课程分类ID
        if(null != dto.getCourseTypeId()){
            boolQueryBuilder.filter(QueryBuilders.termQuery("courseTypeId", dto.getCourseTypeId()));
        }
        //等级名字
        if(StringUtils.isNotEmpty(dto.getGradeName())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("gradeName", dto.getGradeName()));
        }
        //机构名字
        if(StringUtils.isNotEmpty(dto.getTenantName())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("tenantName", dto.getTenantName()));
        }
        //价格查询
        if(null != dto.getPriceMax()){ // 最大值
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(dto.getPriceMax()));
        }
        if(null != dto.getPriceMin()){ // 最小值
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(dto.getPriceMin()));
        }

        //关联查询 就是将filter和must中的一起查询
        searchQueryBuilder.withQuery(boolQueryBuilder);

        // 高亮
        HighlightBuilder.Field field = new HighlightBuilder.Field("name") // 对哪个进行字段高亮
                .preTags("<span style='color:red'>")  // 对高亮字段添加标签头样式
                .postTags("</span>"); // 对高亮字段添加标签尾
        searchQueryBuilder.withHighlightFields(field);

        // 聚合
        // 等级聚合
        TermsAggregationBuilder gradeNameAgg = AggregationBuilders.terms("gradeNameAgg").field("gradeName");
        // 机构聚合
        TermsAggregationBuilder tenantNameAgg = AggregationBuilders.terms("tenantNameAgg").field("tenantName");

        searchQueryBuilder.addAggregation(gradeNameAgg).addAggregation(tenantNameAgg);

        // 创建查询条件
        SearchQuery searchQuery = searchQueryBuilder.build();

        // 通过查询条件获取数据
        //Page<CourseDoc> page = repository.search(searchQuery);
        // 通过原生的es映射获取高亮数据  因为springboot整合的es不支持高亮
        AggregatedPage<CourseDoc> page = template.queryForPage(searchQuery, CourseDoc.class, resultMapper);
        //聚合结果
        Map<String,List<TermsAggBucket>> termsAggResult = new HashMap<>();
        // 处理聚合结果
        Map<String, Aggregation> aggregationMap = page.getAggregations().asMap(); // 查询所有的聚合结果并装换为map
        aggregationMap.keySet().forEach(key->{ // 遍历聚合结果并获取其中的key   key : 聚合的名字
            //Bucke列表
            List<TermsAggBucket> termsAggBuckets = new ArrayList<>();

            // 值aggregation ：
            StringTerms aggregation = (StringTerms) aggregationMap.get(key); // 通过key获取map
            aggregation.getBuckets().forEach(bucket -> {
                //每一个bucket 名字
                String name = bucket.getKey().toString();
                //数量
                long docCount = bucket.getDocCount();
                //一个 Bucket转成一个 TermsAggBucket对象
                termsAggBuckets.add(new TermsAggBucket(name , docCount));
            });
            //加入到聚合结果
            termsAggResult.put(key,termsAggBuckets );
        });
        return new AggPageList(page.getTotalElements() , page.getContent(),termsAggResult);

    }

}
